package com.pdool.game.logic.mgr;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.pdool.common.constants.Constant;
import com.pdool.common.constants.MsgId;
import com.pdool.common.dict.AICardVo;
import com.pdool.common.dict.AreaEffectVo;
import com.pdool.common.dict.BasePropVo;
import com.pdool.common.dto.room.CreateRoomInfo;
import com.pdool.common.dto.room.RoleFightInitInfo;
import com.pdool.common.entity.RoleInfoEntity;
import com.pdool.common.entity.RoleNumInfoEntity;
import com.pdool.common.msg.match.EnterRoomSTC;
import com.pdool.game.core.msg.RoomRemoteMgr;
import com.pdool.game.dict.AICardConfig;
import com.pdool.game.dict.AreaEffectConfig;
import com.pdool.game.dict.BasePropConfig;
import com.pdool.game.logic.domain.MatchRoleInfo;
import com.pdool.game.logic.domain.entity.vo.CardGroupVo;
import com.pdool.game.logic.enums.LogPointType;
import com.pdool.game.logic.enums.NumTypeEnum;
import com.pdool.game.logic.service.CardGroupService;
import com.pdool.game.logic.service.RoleService;
import com.pdool.game.logic.util.LogUtil;
import com.pdool.game.util.SessionUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.stream.Collectors;

@Component
@Data
@Slf4j
public class MatchMgr implements InitializingBean {
    @Resource
    RoleService roleService;

    @Resource
    AICardConfig aiCardConfig;
    @Resource
    AreaEffectConfig areaEffectConfig;
    @Resource
    CardGroupService cardGroupService;
    @Autowired
    BasePropConfig basePropConfig;


    private static MatchMgr instance;

    public static MatchMgr getInstance() {
        return instance;
    }

    @Override
    public void afterPropertiesSet() {
        instance = this;
    }

    private final Map<Integer, LinkedBlockingQueue<MatchRoleInfo>> queueMap = new HashMap<>();

    Map<Long,String> roleRoomMap = new ConcurrentHashMap<>();

    public void matchReq(MatchRoleInfo matchRoleInfo) {
        int matchGroup = matchRoleInfo.getMatchGroup();
        LinkedBlockingQueue<MatchRoleInfo> matchRoleInfos = queueMap.computeIfAbsent(matchGroup, group -> new LinkedBlockingQueue<>());
        matchRoleInfos.offer(matchRoleInfo);
        checkMatch();
    }

    /**
     * 1s扫描一次，超时之后直接匹配机器人
     * 加入的时候匹配
     */
    public void checkMatch() {
        //   匹配完成后创建房间
        for (LinkedBlockingQueue<MatchRoleInfo> value : queueMap.values()) {
            if (value.size() == 1) {
                checkTimeOut(value);
                continue;
            }
            while (value.size() >= 2) {
                MatchRoleInfo left = value.poll();
                MatchRoleInfo right = value.poll();
                if (left != null && right != null) {
                    enterRoom(left, right);
                }
            }
        }
    }

    /**
     * 检查超时的
     *
     * @param queue
     */
    private void checkTimeOut(LinkedBlockingQueue<MatchRoleInfo> queue) {
        MatchRoleInfo peek = queue.peek();
        if (peek == null) {
            return;
        }
        long between = DateUtil.between(new Date(), peek.getRegTime(), DateUnit.SECOND);
        if (between < Constant.MATCH_TIME_OUT) {
            return;
        }
        queue.remove(peek);

        //  匹配机器人
        MatchRoleInfo robotInfo = createRobotInfo(peek);
        enterRoom(peek, robotInfo);
    }

    /**
     * 创建机器人
     *
     * @param peek
     * @return
     */
    private MatchRoleInfo createRobotInfo(MatchRoleInfo peek) {
        long roleId = peek.getRoleId();
        RoleNumInfoEntity roleNumInfo = roleService.getRoleNumInfo(roleId, NumTypeEnum.BATTLE_COUNT);
        Long num = roleNumInfo.getNum();

        Collection<AICardVo> values = aiCardConfig.getDataMap().values();
        List<AICardVo> collect = values.stream().filter(value -> (num >= value.getBattleNum().getKey() && value.getBattleNum().getValue() > num)).collect(Collectors.toList());

        int size = collect.size();
        int i = RandomUtil.randomInt(0, size);
        AICardVo aiCardVo = collect.get(i);
        MatchRoleInfo matchRoleInfo = new MatchRoleInfo();
        matchRoleInfo.setRoleId(aiCardVo.getId() * -1);
        return matchRoleInfo;
    }

    /**
     * 进入战场
     *
     * @param matchRoleInfos
     */
    public void enterRoom(MatchRoleInfo... matchRoleInfos) {
        CreateRoomInfo createRoomInfo = new CreateRoomInfo();
        selectBattleArea(createRoomInfo);
        EnterRoomSTC.Builder builder = EnterRoomSTC.newBuilder();

        String logMsg = "";
        for (int i = 0; i < matchRoleInfos.length; i++) {
            MatchRoleInfo matchRoleInfo = matchRoleInfos[i];
            RoleFightInitInfo roleFightInitInfo = makeData(matchRoleInfo);
            //  设置阵营
            roleFightInitInfo.setPos(i);
            EnterRoomSTC.RoleInfoItem item = makeRoleInfo(matchRoleInfo, i);
            builder.addVs(item);
            createRoomInfo.getFightInfoList().add(roleFightInitInfo);

            logMsg += matchRoleInfo.getRoleId() + " =====>   ";
        }
        log.error(logMsg);


        String roomId = RoomRemoteMgr.getInstance().getRoomService().createRoom(createRoomInfo);
        builder.setRoomId(roomId);

        for (int i = 0; i < createRoomInfo.getFightInfoList().size(); i++) {
            RoleFightInitInfo roleFightInitInfo = createRoomInfo.getFightInfoList().get(i);
            long roleId = roleFightInitInfo.getRoleId();
            if (roleId > 0) {
                roleRoomMap.put(roleId,roomId);
                //  推送进入房间
                SessionUtil.pushMsg(roleId, MsgId.STC_CREATE_ROOM_SUCCESS, builder.build());

                LogUtil.getInstance().recordLog(roleId, LogPointType.BATTLE_COUNT, 1);
            }

        }
    }

    private EnterRoomSTC.RoleInfoItem makeRoleInfo(MatchRoleInfo matchRoleInfo, int i) {
        long roleId = matchRoleInfo.getRoleId();
        EnterRoomSTC.RoleInfoItem.Builder builder = EnterRoomSTC.RoleInfoItem.newBuilder();
        if (roleId < 0) {
            builder.setRoleId(roleId);
        } else {
            RoleInfoEntity roleInfoEntity = roleService.queryUserOne(roleId);
            builder.setHead(roleInfoEntity.getHead());
            builder.setName(roleInfoEntity.getName());
        }
        builder.setPos(i);
        return builder.build();
    }

    /**
     * 选择三个战场
     *
     * @param createRoomInfo
     */
    private void selectBattleArea(CreateRoomInfo createRoomInfo) {
        BasePropVo byKey = basePropConfig.getByKey(Constant.PROP_AREA_COUNT);
        String value = byKey.getValue();
        int areaCount = Integer.parseInt(value);
        Set<AreaEffectVo> areaEffectVos = RandomUtil.randomEleSet(areaEffectConfig.getDataMap().values(), areaCount);
        List<Integer> collect = areaEffectVos.stream().map(AreaEffectVo::getId).collect(Collectors.toList());

////        //  TODO 先写死
//        collect.clear();
//        collect.add(21);
//        collect.add(5);
        createRoomInfo.setAreaInfo(collect);
    }

    /**
     * 组织战斗数据
     *
     * @param matchInfo
     * @return
     */
    public RoleFightInitInfo makeData(MatchRoleInfo matchInfo) {
        RoleFightInitInfo roleFightInitInfo = new RoleFightInitInfo();
        long roleId = matchInfo.getRoleId();
        roleFightInitInfo.setRoleId(matchInfo.getRoleId());
        //  玩家
        if (roleId > 0) {
            CardGroupVo cardGroup = cardGroupService.getCardGroup(roleId, matchInfo.getCardGroupIndex());
            List<Integer> cardList = new ArrayList<>(cardGroup.getCardGroupList());
            roleFightInitInfo.setCardList(cardList);
        } else {
            //  机器人
            AICardVo aiCardVo = aiCardConfig.getDataMap().get(Math.abs(Math.toIntExact(matchInfo.getRoleId())));
            roleFightInitInfo.setCardList(aiCardVo.getCardList());
        }
        return roleFightInitInfo;
    }
}
